﻿// Decompiled with JetBrains decompiler
// Type: Netick.FastAllocator
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Collections.Generic;

#nullable disable
namespace Netick;

internal class FastAllocator
{
  internal const int SmallBlockSizeBytes = 32 /*0x20*/;
  internal const int MediumBlockSizeBytes = 128 /*0x80*/;
  internal const int BigBlockSizeBytes = 512 /*0x0200*/;
  internal const int BlocksPerLevel = 512 /*0x0200*/;
  internal Queue<FastAllocator.MemBlock> _small;
  internal Queue<FastAllocator.MemBlock> _medium;
  internal Queue<FastAllocator.MemBlock> _big;
  internal NetickAllocator _allocator;

  public unsafe FastAllocator(long initialSizeBytes)
  {
    this._allocator = new NetickAllocator(initialSizeBytes);
    this._small = new Queue<FastAllocator.MemBlock>(512 /*0x0200*/);
    this._medium = new Queue<FastAllocator.MemBlock>(512 /*0x0200*/);
    this._big = new Queue<FastAllocator.MemBlock>(512 /*0x0200*/);
    FastAllocator.MemBlock memBlock;
    for (int index = 0; index < 512 /*0x0200*/; ++index)
    {
      memBlock = new FastAllocator.MemBlock();
      memBlock.Ptr = new IntPtr(this._allocator.SafeMalloc(32UL /*0x20*/, out int _, out long _, true));
      memBlock.Size = 32 /*0x20*/;
      this._small.Enqueue(memBlock);
    }
    for (int index = 0; index < 512 /*0x0200*/; ++index)
    {
      memBlock = new FastAllocator.MemBlock();
      memBlock.Ptr = new IntPtr(this._allocator.SafeMalloc(128UL /*0x80*/, out int _, out long _, true));
      memBlock.Size = 128 /*0x80*/;
      this._medium.Enqueue(memBlock);
    }
    for (int index = 0; index < 512 /*0x0200*/; ++index)
    {
      memBlock = new FastAllocator.MemBlock();
      memBlock.Ptr = new IntPtr(this._allocator.SafeMalloc(512UL /*0x0200*/, out int _, out long _, true));
      memBlock.Size = 512 /*0x0200*/;
      this._big.Enqueue(memBlock);
    }
  }

  public unsafe void* Allocate(long sizeBytes)
  {
    if (sizeBytes <= 32L /*0x20*/)
      return this.AllocateBlock(this._small, 32 /*0x20*/);
    if (sizeBytes <= 128L /*0x80*/)
      return this.AllocateBlock(this._medium, 128 /*0x80*/);
    return sizeBytes <= 512L /*0x0200*/ ? this.AllocateBlock(this._big, 512 /*0x0200*/) : this._allocator.SafeMalloc((ulong) sizeBytes, out int _, out long _, true);
  }

  public unsafe void Free(void* ptr, int sizeBytes)
  {
    if (sizeBytes <= 32 /*0x20*/)
      this.FreeBlock(ptr, this._small, 32 /*0x20*/);
    else if (sizeBytes <= 128 /*0x80*/)
      this.FreeBlock(ptr, this._medium, 128 /*0x80*/);
    else if (sizeBytes <= 512 /*0x0200*/)
      this.FreeBlock(ptr, this._big, 512 /*0x0200*/);
    else
      this._allocator.Free(ptr);
  }

  private unsafe void* AllocateBlock(Queue<FastAllocator.MemBlock> pool, int levelSizeBytes)
  {
    FastAllocator.MemBlock memBlock;
    if (pool.Count < 1)
      memBlock = new FastAllocator.MemBlock()
      {
        Ptr = new IntPtr(this._allocator.SafeMalloc((ulong) levelSizeBytes, out int _, out long _, true)),
        Size = levelSizeBytes
      };
    else
      memBlock = pool.Dequeue();
    return memBlock.Ptr.ToPointer();
  }

  private unsafe void FreeBlock(void* ptr, Queue<FastAllocator.MemBlock> pool, int levelSizeBytes)
  {
    FastAllocator.MemBlock memBlock = new FastAllocator.MemBlock()
    {
      Ptr = new IntPtr(ptr),
      Size = levelSizeBytes
    };
    pool.Enqueue(memBlock);
  }

  internal struct MemBlock
  {
    public IntPtr Ptr;
    public int Size;
  }
}
